//
//  NetConnection.m
//  LegoClient
//
//  Created by Balazs Faludi on 02.01.10.
//  Copyright 2010 Universität Basel. All rights reserved.
//

#import "NetConnection.h"
#import "NetMessage.h"

@interface NetConnection () 

@property (nonatomic, retain) NSInputStream *inputStream;
@property (nonatomic, retain) NSOutputStream *outputStream;
@property (nonatomic, retain) NSMutableData *currentDownload;
@property (nonatomic, retain) NSMutableData *currentUpload;

@end


@implementation NetConnection

@synthesize delimiter;
@synthesize inputStream = _inputStream;
@synthesize outputStream = _outputStream;
@synthesize currentDownload = _currentDownload;
@synthesize currentUpload = _currentUpload;
@synthesize delegate;

- (id)initWithInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream
{
	self = [super init];
	if (self != nil) {
		self.delimiter = @"\n";
		_outputHasSpaceAvailable = NO;
		self.inputStream = [inputStream retain];
		self.outputStream = [outputStream retain];
		self.inputStream.delegate = self;
		self.outputStream.delegate = self;
		[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
		[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
		[self.inputStream open];
		[self.outputStream open];
	}
	return self;
}

- (void) dealloc
{
	self.inputStream = nil;
	self.outputStream = nil;
	self.delegate = nil;
	self.currentDownload = nil;
	self.delimiter = nil;
	[super dealloc];
}

- (void)analyzeDownload {
	NSString *str = [[NSString alloc] initWithData:self.currentDownload encoding:NSASCIIStringEncoding];
	NSArray *parts = [str componentsSeparatedByString:self.delimiter];
	
	for(int i = 0; i < [parts count] - 1; i++) {
		NSString *content = [parts objectAtIndex:i];
		if([content hasPrefix:kNetConnectionPingHeader]) {
			NetMessage *response = [[NetMessage alloc] initWithString:content];
			[self sendMessage:response];
		}
		else if(delegate && [delegate respondsToSelector:@selector(connection:receivedMessage:)]) {
			NetMessage *newMessage = [[NetMessage alloc] initWithString:content];
			[delegate connection:self receivedMessage:newMessage];
			[newMessage release];
		}
	}
	
	self.currentDownload = [[NSMutableData alloc] initWithData:[[parts lastObject] dataUsingEncoding:kNetMessageEncoding]];
}

- (void)handleConnectionLost {
	NSLog(@"Connection lost.");
}

- (BOOL)sendAvailableData {
	if(!self.currentUpload) return NO;
	if([self.currentUpload length] < 1) return NO;
	if(!self.outputStream) {
		[self handleConnectionLost];
		return NO;
	}
	NSInteger   bytesWritten;
	bytesWritten = [self.outputStream write:[self.currentUpload bytes] maxLength:[self.currentUpload length]];
	if (bytesWritten == -1) {
		NSLog(@"Network write error: %@", self.outputStream.streamError.description);
	} else if(bytesWritten == 0) {
		return NO;
	}
	if(self.currentUpload.length == bytesWritten) {
		NSMutableData *newData = [[NSMutableData alloc] initWithCapacity:128];
		self.currentUpload = newData;
		[newData release];
	} else {
		NSRange range; range.location = bytesWritten; range.length = self.currentUpload.length - bytesWritten;
		NSMutableData *newData = [[NSMutableData alloc] initWithData:[self.currentUpload subdataWithRange:range]];
		self.currentUpload = newData;
	}
	return YES;
}

- (void)handleStreamError {
	[(NSInputStream *)self.inputStream close];
	[(NSOutputStream *)self.outputStream close];
	if(delegate && [delegate respondsToSelector:@selector(connectionLost:)]) {
		[delegate connectionLost:self];
	}
}

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)event {
    switch(event) {
        case NSStreamEventHasBytesAvailable:
            if (!self.currentDownload) {
                self.currentDownload = [[NSMutableData alloc] initWithCapacity:409600];
            }
            uint8_t readBuffer[4096];
            int amountRead = 0;
            NSInputStream * is = (NSInputStream *)aStream;
            amountRead = [is read:readBuffer maxLength:4096];
            [self.currentDownload appendBytes:readBuffer length:amountRead];
			[self analyzeDownload];
            break;
		case NSStreamEventHasSpaceAvailable:
			_outputHasSpaceAvailable = ![self sendAvailableData];
			break;
        case NSStreamEventEndEncountered:
            //[self handleStreamError];
			break;
		case NSStreamEventErrorOccurred:
			[self handleStreamError];
            break;
        default:
            break;
    }
}

- (void)sendMessage:(NetMessage *)message {
	//NSLog(@"Send: %@", [message stringValue]);
	if (!self.currentUpload) {
		self.currentUpload = [[NSMutableData alloc] initWithCapacity:409600];
	}
	NSString *string = [NSString stringWithFormat:@"%@\n", [message stringValue]];
	[self.currentUpload appendData:[string dataUsingEncoding:kNetMessageEncoding]];
	if(_outputHasSpaceAvailable) {
		[self sendAvailableData];
		_outputHasSpaceAvailable = NO;
	}
}


@end
